package com.mall4j.cloud.product.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mall4j.cloud.product.dto.RequestResourceDTO;
import com.mall4j.cloud.product.mapper.ResourceMapper;
import com.mall4j.cloud.product.model.ResourceEntity;
import com.mall4j.cloud.product.service.ResourceService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service("resourceService")
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, ResourceEntity> implements ResourceService {

    @Autowired
    ResourceMapper resourceMapper;

    /*
     * 接收ERP资源推送
     * */
    @Override
    public void handleReceive(List<RequestResourceDTO> resourceDTOList) {
        if (resourceDTOList == null || resourceDTOList.size() == 0) {
            return;
        }

        List<ResourceEntity> resourceEntityList = this.requestDto2entity(resourceDTOList);
        this.saveOrUpdateByErpId(resourceEntityList);
    }

    /*
     * dto转实体类
     * */
    public List<ResourceEntity> requestDto2entity(List<RequestResourceDTO> list) {
        List<ResourceEntity> resultList = new ArrayList<>();
        for (RequestResourceDTO oneDTO : list) {
            ResourceEntity oneEntity = new ResourceEntity();
            BeanUtils.copyProperties(oneDTO, oneEntity);
            oneEntity.setErpId(oneDTO.getResourceId());
            oneEntity.setAliasProductName(oneDTO.getProductName());
            oneEntity.setAliasPlace(oneDTO.getPlace());
            oneEntity.setAliasWarehouse(oneDTO.getWarehouse());
            resultList.add(oneEntity);
        }
        return resultList;
    }

    /*
     * 根据资源erpId判断是保存还是修改
     *
     * 优化策略: 5000 3S    10000 6S
     * 1.查询出数据库所有erpId还是查所需要的（查所需要的就行了，减少后面过滤工作量）
     * 2.erpId需不要需要加索引（先不加，现在主要是新增，后面发现查询比较多再加）
     * 3.过滤用List还是用Set（用Set的contains()方法，时间复杂度是O(1)）
     * 4.批量新增或更新用foreach一条sql处理 (数据库连接需要开启批处理参数 rewriteBatchedStatements=true) (万级数据没问题，再多要分批处理或其他方案)
     * 5.无需事务（尽力去新增，更新，通知）
     * 6.锁（加锁保证请求次序。需求无需高并发，尽快同步数据就行）（后期如果有并发，考虑MQ）
     * */
    public synchronized void saveOrUpdateByErpId(List<ResourceEntity> list) {
        StopWatch sw = new StopWatch();

        sw.start("查询");
        //查出数据库里所有erpId(实际查所需的就行了)
        Set<String> temIdList = list.stream().map(ResourceEntity::getErpId).collect(Collectors.toSet());
        Set<String> allErpIdList = resourceMapper.getAllErpIdList(temIdList);
        sw.stop();

        sw.start("过滤处理");
        //哪些资源已经有了，需要更新
        List<ResourceEntity> updateList = list.stream().filter((ResourceEntity one) -> allErpIdList.contains(one.getErpId())).collect(Collectors.toList());
        //哪些资源没有需要新增
        List<ResourceEntity> saveList = list.stream().filter((ResourceEntity one) -> !allErpIdList.contains(one.getErpId())).collect(Collectors.toList());
        sw.stop();

        sw.start("更新");
        //执行
        if (updateList != null && updateList.size() > 0) {
            resourceMapper.updateBatchbyErpId(updateList);
        }
        sw.stop();

        sw.start("新增");
        //执行
        if (saveList != null && saveList.size() > 0) {
            resourceMapper.saveList(saveList);
        }
        sw.stop();

        System.out.println(sw.prettyPrint());
        System.out.println(sw.getTotalTimeSeconds());
    }
}
